'''
监测用的类
TransactionFlowMonitor: 监测交易流量，包括存款、贷款、债券交易等
BalanceSheetMonitor: 监测资产负债表，包括银行、公司、居民的资产、负债等
'''
from operator import inv
# from re import T
import numpy as np
import pandas as pd

from typing import List

from utils import apt, TransactionFlowItem, EpisodeItem, TransactionFlowAgentItem

from agent import Firms
from episode import Events


class TransactionFlowMonitor:
    """_summary_: 监控交易流量，包括存款、贷款、债券交易等
    Returns:
        _type_: _description_
    """
    # 记录经济在一段时间的资金流量表
    def __init__(self, e: Events):
        self.tf_item = TransactionFlowItem()
        self.ep_item = EpisodeItem()
        self.e = e
        h_logs = {d.uuid: d for h in self.e.credit_market.households for d in h.log}
        c_logs = {d.uuid: d for c in self.e.credit_market.c_firms for d in c.log}
        k_logs = {d.uuid: d for k in self.e.credit_market.k_firms for d in k.log}
        b_logs = {d.uuid: d for b in self.e.credit_market.banks for d in b.log}
        g_logs = {d.uuid: d for d in self.e.gov.log}
        self.logs = {'h': h_logs, 'c': c_logs, 'k': k_logs, 'b': b_logs, 'g': g_logs}
        # 中央银行资产负债变动
        self.cb_info_episode_end = self.e.credit_market.central_bank.yearly_info[self.e.year]
        self.cb_delta_cash_advances = self.cb_info_episode_end.delta_cash_advances
        self.cb_delta_reserves = self.cb_info_episode_end.delta_reserves
        self.cb_delta_bonds = self.cb_info_episode_end.delta_bonds
        # 消费
        self.household_consumption = self.sum_two_filter('h', self.tf_item.Consumption, self.ep_item.cash_flow_consumption)
        self.c_firm_consumption = self.sum_two_filter('c', self.tf_item.Consumption, self.ep_item.cash_flow_consumption)
        # 工资
        self.household_wages = self.sum_two_filter('h', self.tf_item.Wages, '发')  # 对ep_item 公有项提取，都包含 "发" 字
        self.c_firm_wages = self.sum_two_filter('c', self.tf_item.Wages, self.ep_item.c_firm_pay_wage)
        self.k_firm_wages = self.sum_two_filter('k', self.tf_item.Wages, self.ep_item.k_firm_pay_wage)
        self.gov_wages = self.sum_two_filter('g', self.tf_item.Wages, self.ep_item.gov_pay_wage)
        # 救济金
        self.household_dole = self.sum_two_filter('h', self.tf_item.Dole, self.ep_item.gov_pay_dole)
        self.gov_dole = self.sum_two_filter('g', self.tf_item.Dole, self.ep_item.gov_pay_dole)
        # 投资
        self.c_firm_investment = self.sum_two_filter('c', self.tf_item.Investments, self.ep_item.cash_flow_capital)
        self.k_firm_sell_inv = self.sum_two_filter('k', self.tf_item.Investments, self.ep_item.cash_flow_capital)
        # 存货重估
        self.c_firm_inv_revalue = self.sum_two_filter('c', self.tf_item.CG_on_inventories, self.ep_item.c_firm_inv_revalue)
        self.k_firm_inv_revalue = self.sum_two_filter('k', self.tf_item.CG_on_inventories, self.ep_item.k_firm_inv_revalue)
        # 折旧
        self.c_firm_amortization = self.sum_two_filter('c', self.tf_item.Capital_amortization, self.ep_item.capital_amortization)
        # 税收
        self.household_pay_tax = self.sum_two_filter('h', self.tf_item.Taxes, self.ep_item.household_pay_tax)
        self.c_firm_pay_tax = self.sum_two_filter('c', self.tf_item.Taxes, self.ep_item.c_firm_pay_tax)
        self.k_firm_pay_tax = self.sum_two_filter('k', self.tf_item.Taxes, self.ep_item.k_firm_pay_tax)
        self.bank_pay_tax = self.sum_two_filter('b', self.tf_item.Taxes, self.ep_item.bank_pay_tax)
        self.gov_collect_tax = self.sum_two_filter('g', self.tf_item.Taxes, '税')  # 对ep_item 公有项提取 都包含 "税" 字
        # 存款利息
        self.household_dep_interest = self.sum_two_filter('h', self.tf_item.Dep_interest, self.ep_item.bank_pay_dep_int_to_h)
        self.c_firm_dep_interest = self.sum_two_filter('c', self.tf_item.Dep_interest, self.ep_item.bank_pay_dep_int_to_c)
        self.k_firm_dep_interest = self.sum_two_filter('k', self.tf_item.Dep_interest, self.ep_item.bank_pay_dep_int_to_k)
        self.bank_pay_dep_interest = self.sum_two_filter('b', self.tf_item.Dep_interest, '存款利息')  # '都包含 "存款利息"'
        # 债券利息
        self.bank_bond_interest = self.sum_two_filter('b', self.tf_item.Bonds_interest, self.ep_item.gov_pay_int_to_bank)
        self.cb_bond_interest = self.sum_two_filter('g', self.tf_item.Bonds_interest, self.ep_item.gov_pay_int_to_cb_bank)
        self.gov_pay_bond_interest = self.sum_two_filter('g', self.tf_item.Bonds_interest, "国债利息")
        # 贷款利息
        self.c_firm_pay_loan_int = self.sum_two_filter('c', self.tf_item.Loans_interest, self.ep_item.c_firm_pay_loan_int)
        self.k_firm_pay_loan_int = self.sum_two_filter('k', self.tf_item.Loans_interest, self.ep_item.k_firm_pay_loan_int)
        self.bank_collect_loan_int = self.sum_two_filter('b', self.tf_item.Loans_interest, '贷款利息')  # 贷款利息
        # cash advance
        self.bank_cash_advance_int = self.sum_two_filter('b', self.tf_item.Advances_interest, self.ep_item.cash_advance_int)
        self.bank_cash_advance_repayment = self.sum_two_filter('b', self.tf_item.Advances_interest,
                                                               self.ep_item.cash_advance_repayment)
        # 股利
        self.c_firm_div = self.sum_two_filter('c', self.tf_item.Profits, self.ep_item.c_firm_pay_div)
        self.c_firm_keep_profits = self.sum_two_filter('c', self.tf_item.Profits, self.ep_item.c_firm_keep_div)
        self.k_firm_div = self.sum_two_filter('k', self.tf_item.Profits, self.ep_item.k_firm_pay_div)
        self.k_firm_keep_profits = self.sum_two_filter('k', self.tf_item.Profits, self.ep_item.k_firm_keep_div)
        self.bank_div = self.sum_two_filter('b', self.tf_item.Profits, self.ep_item.bank_pay_div)
        self.bank_keep_profits = self.sum_two_filter('b', self.tf_item.Profits, self.ep_item.bank_keep_div)
        self.household_collect_div = self.sum_two_filter('h', self.tf_item.Profits, '股利')
        # 发行新债券
        self.banks_buy_new_bonds = self.sum_two_filter('b', self.tf_item.delta_Gov_bonds, self.ep_item.banks_buy_gov_issue_bonds)
        # 贷款偿还与新增贷款
        self.c_firm_delta_loans_new = self.sum_two_filter('c', self.tf_item.delta_loans, self.ep_item.c_firm_new_loan)
        self.c_firm_delta_loans_new_df = self.to_df_two_filter('c', self.tf_item.delta_loans, self.ep_item.c_firm_new_loan)

        self.c_firm_delta_loans_repay = self.sum_two_filter('c', self.tf_item.delta_loans, self.ep_item.c_firm_loan_repayment)
        self.c_firm_delta_loans_repay_df = self.to_df_two_filter('c', self.tf_item.delta_loans, self.ep_item.c_firm_loan_repayment)

        self.k_firm_delta_loans_new = self.sum_two_filter('k', self.tf_item.delta_loans, self.ep_item.k_firm_new_loan)
        self.k_firm_delta_loans_new_df = self.to_df_two_filter( 'k', self.tf_item.delta_loans, self.ep_item.k_firm_new_loan)

        self.k_firm_delta_loans_repay = self.sum_two_filter('k', self.tf_item.delta_loans, self.ep_item.k_firm_loan_repayment)
        self.k_firm_delta_loans_repay_df = self.to_df_two_filter('k', self.tf_item.delta_loans, self.ep_item.k_firm_loan_repayment)

        self.bank_delta_loans_new = self.sum_two_filter('b', self.tf_item.delta_loans, '新增贷款')  # 应等于c+k新增
        self.bank_delta_loans_repay = self.sum_two_filter('b', self.tf_item.delta_loans, '本金偿还')  # 应等于c+k本金偿还
        # 居民存款的变动
        self.household_dep_increase = self.sum_item_filter('h', '居民存款增加')
        self.household_dep_decrease = self.sum_item_filter('h', '居民存款减少')
        # 消费品公司存款
        self.c_firm_dep_increase = self.sum_item_filter('c', '消费品公司存款增加')
        self.c_firm_dep_decrease = self.sum_item_filter('c', '消费品公司存款减少')
        self.k_firm_dep_increase = self.sum_item_filter('k', '资本品公司存款增加')
        self.k_firm_dep_decrease = self.sum_item_filter('k', '资本品公司存款减少')
        # 银行记录存款
        self.bank_dep_increase = self.sum_item_filter('b', '银行存款负债增加')
        self.bank_dep_decrease = self.sum_item_filter('b', '银行存款负债减少')
        # 银行记录准备金
        self.bank_reserve_increase = self.sum_item_filter('b', '银行准备金增加')
        self.bank_reserve_decrease = self.sum_item_filter('b', '银行准备金减少')

    def check_all_agents_consistent(self):
        for c in self.e.credit_market.c_firms:
            c.valid_accounting_consistent()
            c.save_bs_tf_table()
        print(">>>> 【-----消费品公司一致性检验通过------】")
        for k in self.e.credit_market.k_firms:
            k.valid_accounting_consistent()
            k.save_bs_tf_table()
        print(">>>> 【-----资本品公司一致性检验通过------】")
        sum_df =[]
        for b in self.e.credit_market.banks:
            df = b.valid_accounting_consistent()
            sum_df.append(df)
        df_all = sum(d for d in sum_df)
        print(">>>> 【-----银行一致性检验通过------】")
        print(df_all)

    def valid_consumption_firm_flow_consistent(self, id_of_company):
        c_firm = self.e.credit_market.c_firms_map[id_of_company]
        df = pd.DataFrame(c_firm.log)
        # 资金流入
        # 居民消费，消费品公司获得的现金
        consumption = df[df['item'] == self.ep_item.cash_flow_consumption]['amount'].sum()
        # 消费品公司的存款利息
        deposit_interests = df[df['item'] == self.ep_item.bank_pay_dep_int_to_c]['amount'].sum()
        new_loans = df[df['item'] == self.ep_item.c_firm_new_loan]['amount'].sum()
        # 资金流出
        loan_interests = df[df['item'] == self.ep_item.c_firm_pay_loan_int]['amount'].sum()
        wages = df[df['item'] == self.ep_item.c_firm_pay_wage]['amount'].sum()
        # 消费品公司的投资
        investment = df[df['item'] == self.ep_item.cash_flow_capital]['amount'].sum()
        taxes = df[df['item'] == self.ep_item.c_firm_pay_tax]['amount'].sum()
        c_firm_pay_div = df[df['item'] == self.ep_item.c_firm_pay_div]['amount'].sum()
        c_firm_keep_div = df[df['item'] == self.ep_item.c_firm_keep_div]['amount'].sum()
        dividends = c_firm_pay_div + c_firm_keep_div
        # 偿还贷款
        repay_loans = df[df['item'] == self.ep_item.c_firm_loan_repayment]['amount'].sum()
        # 不产生现金流项目
        change_inventory = df[df['item'] == self.ep_item.c_firm_inv_revalue]['amount'].sum()
        capital_amortization = df[df['item'] == self.ep_item.capital_amortization]['amount'].sum()
        keep_profits = df[df['item'] == self.ep_item.c_firm_keep_div]['amount'].sum()
        t_in = f"收入:{consumption:.1f},存款利息:{deposit_interests:.1f},新贷款:{new_loans:.1f}"
        t_out1 = f"支出:贷款利息:{loan_interests:.1f},工资:{wages:.1f},投资:{investment:.1f}"
        t_out2 = f"税金:{taxes:.1f},股息:{dividends:.1f},偿还贷款:{repay_loans:.1f}"
        sum_in = consumption + deposit_interests + new_loans
        sum_out = loan_interests + wages + investment + taxes + dividends + repay_loans
        # print(t_in, t_out1, t_out2)
        # print(f"验证存款流入项:{sum_in:.1f} 存款流出项:{sum_out:.1f}")
        dic_consumption = {
            self.tf_item.Consumption: [consumption,0],
            self.tf_item.Wages: [-wages,0],
            self.tf_item.CG_on_inventories:[change_inventory,-change_inventory],
            self.tf_item.Investments:[0, -investment],
            self.tf_item.Capital_amortization:[-capital_amortization,capital_amortization],
            self.tf_item.Taxes: [-taxes, 0],
            self.tf_item.Dep_interest:[deposit_interests, 0],
            self.tf_item.Loans_interest:[-loan_interests, 0],
            self.tf_item.Profits:[-dividends, keep_profits],
            self.tf_item.delta_loans:[0, new_loans-repay_loans],
        }
        df_c = pd.DataFrame(dic_consumption)
        df_c.index = ['Con.CA', 'Con.KA']
        df_c['Sum'] = df_c.sum(axis=1)
        df_c = df_c.T
        return df_c, sum_in - sum_out
    
    
    def valid_bank_flow_consistent(self, id_of_bank):
        bank = self.e.credit_market.banks_map[id_of_bank]
        df = pd.DataFrame(bank.log)
        # 银行收入
        c_firm_pay_loan_interests = df[df['item'] == self.ep_item.c_firm_pay_loan_int]['amount'].sum()
        k_firm_pay_loan_interests = df[df['item'] == self.ep_item.k_firm_pay_loan_int]['amount'].sum()
        firm_pay_loan_interests = c_firm_pay_loan_interests + k_firm_pay_loan_interests
        # 债券利息
        bonds_interests = df[df['item'] == self.ep_item.gov_pay_int_to_bank]['amount'].sum()
        # 银行支出
        bank_pay_c_firm_dep_interests = df[df['item'] == self.ep_item.bank_pay_dep_int_to_c]['amount'].sum()
        bank_pay_k_firm_dep_interests = df[df['item'] == self.ep_item.bank_pay_dep_int_to_k]['amount'].sum()
        bank_pay_household_dep_interests = df[df['item'] == self.ep_item.bank_pay_dep_int_to_h]['amount'].sum()
        bank_pay_all_dep_interests = bank_pay_c_firm_dep_interests + bank_pay_k_firm_dep_interests + bank_pay_household_dep_interests
        # 银行发股利
        bank_pay_div = df[df['item'] == self.ep_item.bank_pay_div]['amount'].sum()
        bank_keep_div = df[df['item'] == self.ep_item.bank_keep_div]['amount'].sum()
        # 银行缴税
        bank_pay_tax = df[df['item'] == self.ep_item.bank_pay_tax]['amount'].sum()
        # 资金流出
        dic_bank = {
            self.tf_item.Taxes:[-bank_pay_tax, 0],
            self.tf_item.Dep_interest:[-bank_pay_all_dep_interests, 0],
            self.tf_item.Bonds_interest:[bonds_interests, 0],
            self.tf_item.Loans_interest:[firm_pay_loan_interests, 0],
            self.tf_item.Profits:[-(bank_pay_div + bank_keep_div), bank_keep_div],
        }
        df_b = pd.DataFrame(dic_bank)
        df_b.index = ['Banks CA', 'Banks KA']
        df_b['Sum'] = df_b.sum(axis=1)
        df_b = df_b.T
        return df_b
        
    def to_df_two_filter(self, agents: str, tf_item_str: str, item_str: str):
        """
        根据给定的代理类型、交易流项目和特定项目字符串过滤日志，并将过滤后的日志转换为 DataFrame。

        :param agents: 代理类型，如 'h'（居民）、'c'（消费品公司）等
        :param tf_item_str: 交易流项目，如 'Consumption'、'Wages' 等
        :param item_str: 特定项目字符串，用于进一步过滤日志
        :return: 过滤后的日志转换而成的 DataFrame
        """
        # 从日志字典中获取指定代理类型的日志
        logs = self.logs[agents]
        # 过滤日志，筛选出交易流项目与指定项目匹配且特定项目字符串在日志条目中的记录
        li = [d for _, d in logs.items() if
              d.transaction_flow_item == tf_item_str and item_str in d.item]
        # 将过滤后的日志列表转换为 Pandas DataFrame 并返回
        return pd.DataFrame(li)

    def sum_two_filter(self, agents: str, tf_item_str: str, item_str: str):
        """
        根据给定的代理类型、交易流项目和特定项目字符串过滤日志，并对过滤后的日志中的金额进行求和。

        :param agents: 代理类型，如 'h'（居民）、'c'（消费品公司）等
        :param tf_item_str: 交易流项目，如 'Consumption'、'Wages' 等
        :param item_str: 特定项目字符串，用于进一步过滤日志
        :return: 过滤后的日志中金额的总和
        """
        # 从日志字典中获取指定代理类型的日志
        logs = self.logs[agents]
        # 过滤日志，筛选出交易流项目与指定项目匹配且特定项目字符串在日志条目中的记录，并对金额求和
        return np.sum([d.amount for _, d in logs.items() if
                       d.transaction_flow_item == tf_item_str and item_str in d.item])

    def sum_item_filter(self, agent: str, item_str: str):
        """
        根据给定的代理类型和特定项目字符串过滤日志，并对过滤后的日志中的金额进行求和。

        :param agent: 代理类型，如 'h'（居民）、'c'（消费品公司）等
        :param item_str: 特定项目字符串，用于过滤日志
        :return: 过滤后的日志中金额的总和
        """
        # 从日志字典中获取指定代理类型的日志
        logs = self.logs[agent]
        # 过滤日志，筛选出特定项目字符串在日志条目中的记录，并对金额求和
        return np.sum([d.amount for uuid_, d in logs.items() if item_str in d.item])

    def show_tf_table(self, prt=True):
        """
        显示交易流量表，记录经济在一段时间内的交易流量情况。

        该方法会打印出当前年份和交易流量表，同时返回包含交易流量数据的 DataFrame。
        交易流量表包含了各种交易类型（如消费、工资、税收等）在不同主体（如居民、企业、银行等）之间的流动情况。

        Returns:
            pd.DataFrame: 包含交易流量数据的 DataFrame。
        """
        print(self.e.year, 'Monitor Transaction Flow sheet')
        agt = TransactionFlowAgentItem()
        # 消费交易，记录居民的消费支出和消费品公司的消费收入
        a = {
            self.tf_item.Consumption: {agt.household: -self.household_consumption,
                                  agt.consumption_ca: self.c_firm_consumption},
            # 工资交易，记录居民的工资收入和不同类型公司、政府的工资支出
            self.tf_item.Wages: {
                agt.household: self.household_wages,
                agt.consumption_ca: -self.c_firm_wages,
                agt.capital_ca: -self.k_firm_wages,
                agt.gov: -self.gov_wages
            },
            # 救济金交易，记录居民的救济金收入和政府的救济金支出
            self.tf_item.Dole: {
                agt.household: self.household_dole,
                agt.gov: -self.gov_dole
            },
            # 存货重估交易，记录不同类型公司的存货重估情况
            self.tf_item.CG_on_inventories: {
                agt.consumption_ca: self.c_firm_inv_revalue,
                agt.consumption_ka: -self.c_firm_inv_revalue,
                agt.capital_ca: self.k_firm_inv_revalue,
                agt.capital_ka: -self.k_firm_inv_revalue
            },
            # 投资交易，记录不同类型公司的投资情况
            self.tf_item.Investments: {
                agt.consumption_ka: -self.c_firm_investment,
                agt.capital_ca: self.k_firm_sell_inv
            },
            # 资本品公司的资本折旧交易，记录资本品公司的资本折旧情况
            self.tf_item.Capital_amortization: {
                agt.consumption_ca: -self.c_firm_amortization,
                agt.consumption_ka: self.c_firm_amortization
            },
            # 税收交易，记录不同类型主体的税收支出和收入情况
            self.tf_item.Taxes: {
                agt.household: -self.household_pay_tax,
                agt.capital_ca: -self.k_firm_pay_tax,
                agt.consumption_ca: -self.c_firm_pay_tax,
                agt.bank_ca: -self.bank_pay_tax,
                agt.gov: self.gov_collect_tax
            },
            # 存款利息交易，记录不同类型主体的存款利息情况
            self.tf_item.Dep_interest: {
                agt.household: self.household_dep_interest,
                agt.capital_ca: self.k_firm_dep_interest,
                agt.consumption_ca: self.c_firm_dep_interest,
                agt.bank_ca: -self.bank_pay_dep_interest
            },
            # 债券利息交易，记录不同类型主体的债券利息情况
            self.tf_item.Bonds_interest: {
                agt.bank_ca: self.bank_bond_interest,
                agt.cb_ca: self.cb_bond_interest,
                agt.gov: -self.gov_pay_bond_interest
            },
            # 贷款利息交易，记录不同类型主体的贷款利息情况
            self.tf_item.Loans_interest: {
                agt.consumption_ca: -self.c_firm_pay_loan_int,
                agt.capital_ca: -self.k_firm_pay_loan_int,
                agt.bank_ca: self.bank_collect_loan_int
            },
            # cash advance利息交易，记录不同类型主体的现金提前情况
            self.tf_item.Advances_interest: {
                agt.cb_ca: self.bank_cash_advance_int,
                agt.bank_ca: -self.bank_cash_advance_int
            },
            # 利润分配，记录不同类型主体的股利和利润分配情况
            self.tf_item.Profits: {
                agt.household: self.household_collect_div,
                agt.consumption_ca: -self.c_firm_div - self.c_firm_keep_profits,
                agt.consumption_ka: self.c_firm_keep_profits,
                agt.capital_ca: -self.k_firm_div - self.k_firm_keep_profits,
                agt.capital_ka: self.k_firm_keep_profits,
                agt.bank_ca: -self.bank_div - self.bank_keep_profits,
                agt.bank_ka: self.bank_keep_profits
            },
            # 
            self.tf_item.CB_profits: {
                agt.gov: self.e.gov.receive_cb_profits(),
                agt.cb_ca: -self.e.credit_market.central_bank.profits()
            },
            # 平衡项，记录不同类型主体的存款、贷款和准备金情况
            
            self.tf_item.delta_deposits: {
                agt.household: self.household_dep_decrease - self.household_dep_increase,
                agt.consumption_ka: self.c_firm_dep_decrease - self.c_firm_dep_increase,
                agt.capital_ka: self.k_firm_dep_decrease - self.k_firm_dep_increase,
                agt.bank_ka: self.bank_dep_increase - self.bank_dep_decrease,
                },
            self.tf_item.delta_tr_deposits:{
                agt.gov:-self.e.credit_market.government.delta_treasury_deposit(),
                agt.cb_ka:self.e.credit_market.government.delta_treasury_deposit()
            },
            self.tf_item.delta_advances:{
                agt.bank_ka: self.cb_delta_cash_advances,
                agt.cb_ka: -self.cb_delta_cash_advances
            },
            self.tf_item.delta_reserves: {
                agt.bank_ka: -self.cb_delta_reserves,
                agt.cb_ka: self.cb_delta_reserves
            },
            self.tf_item.delta_Gov_bonds: {
                agt.bank_ka: -self.banks_buy_new_bonds,
                agt.cb_ka: -self.e.credit_market.central_bank.delta_bonds_at_episode_end(),
                agt.gov: self.e.gov.delta_bonds()
            },
            self.tf_item.delta_loans: {
                agt.consumption_ka: self.c_firm_delta_loans_new - self.c_firm_delta_loans_repay,
                agt.capital_ka: self.k_firm_delta_loans_new - self.k_firm_delta_loans_repay,
                agt.bank_ka: self.bank_delta_loans_repay - self.bank_delta_loans_new
            }
        }
        df_tf = pd.DataFrame(a)
        df_tf = df_tf.fillna(0)
        df_tf['sum'] = df_tf.sum(axis=1)
        df_tf = df_tf.T
        df_tf['sum'] = df_tf.sum(axis=1)
        new_cols = [agt.household,
                    agt.consumption_ca, agt.consumption_ka,
                    agt.capital_ca, agt.capital_ka,
                    agt.bank_ca, agt.bank_ka,
                    agt.gov,
                    agt.cb_ca, agt.cb_ka,
                    'sum'
                    ]
        df_tf = df_tf[new_cols]
        # 将小于0.0001的数值替换为0
        df_tf = df_tf.map(lambda x: 0 if 0 < x < 0.0001 else x)
        df_tf = df_tf.map(lambda x: 0 if 0 > x > -0.0001 else x)
        if prt:
            print(df_tf.round(2))
        return df_tf


class BalanceSheetMonitor:
    # 记录经济在任一时刻的资产负债表
    def __init__(self, e: Events):
        self.e = e
        # 存款
        self.households_deposits_as_assets = np.sum([h.deposits_contracts.amount for h in e.credit_market.households])
        self.c_firms_deposits_as_assets = np.sum([c.deposits_contracts.amount for c in e.credit_market.c_firms])
        self.k_firms_deposits_as_assets = np.sum([k.deposits_contracts.amount for k in e.credit_market.k_firms])
        self.deposits_as_assets = \
            self.households_deposits_as_assets + self.c_firms_deposits_as_assets + self.k_firms_deposits_as_assets
        self.deposits_as_debt = self.all_deposits_in_banks_as_debt()
        # 贷款
        self.c_firms_loans_as_dept = self.sum_batch_loans(self.e.credit_market.c_firms)
        self.k_firms_loans_as_dept = self.sum_batch_loans(self.e.credit_market.k_firms)
        self.firms_loans_as_dept = self.c_firms_loans_as_dept + self.k_firms_loans_as_dept
        self.banks_loans_as_assets = self.sum_dict_loans()
        # 债券
        self.central_bank_hold_bonds_as_assets = self.e.credit_market.central_bank.bonds
        self.banks_hold_bonds_as_assets = self.sum_batch_bonds()
        self.gov_bonds_issue_as_dept = np.sum([c.amount for c in self.e.gov.bonds_collection])
        # cash_advance
        self.central_bank_hold_cash_advance_as_assets = self.e.credit_market.central_bank.cash_advances
        self.bank_hold_cash_advance_as_dept = np.sum(
            [b.cash_advance_contracts.amount for b in self.e.credit_market.banks])
        # reserve
        self.bank_hold_reserve_as_assets = np.sum([b.reserve_contract.amount for b in self.e.credit_market.banks])
        self.central_bank_hold_reserve_as_dept = self.e.credit_market.central_bank.reserves
        self.c_firm_sell_consumption_goods_as_flow_in = self.e.credit_market
        # inventory
        self.c_firm_inventories = np.sum(
            [c.consumption_inventory.quantity * c.consumption_inventory.unit_cost for c in self.e.credit_market.c_firms])
        self.k_firm_inventories = np.sum(
            [k.capital_inventory.quantity * k.capital_inventory.price for k in self.e.credit_market.k_firms])
        self.c_firm_capitals = np.sum(
            [c.cal_batch_of_capital_with_price() for c in self.e.credit_market.c_firms]
        )
        self.se = 123

    def check_balance_sheet(self):
        self.check_deposits()
        self.check_loans()
        self.check_bonds()
        self.check_cash_advance()
        self.check_reserves()

    def show_bs_table(self, prt=True):
        """
        资产负债表
        """
        deposits_ = {
            'Households': self.households_deposits_as_assets,
            'Cons.Firms': self.c_firms_deposits_as_assets,
            'Cap.Firms': self.k_firms_deposits_as_assets,
            'Bank': -self.deposits_as_debt,
            'Total': self.deposits_as_assets - self.deposits_as_debt
            }
        loans_ = {
            'Cons.Firms': -self.c_firms_loans_as_dept,
            'Cap.Firms': -self.k_firms_loans_as_dept,
            'Bank': self.banks_loans_as_assets,
            'Total': self.banks_loans_as_assets - self.firms_loans_as_dept}
        con_goods_ = {
            'Cons.Firms': self.c_firm_inventories,
            'Total': self.c_firm_inventories,
        }
        cap_goods_ = {
            'Cons.Firms': self.c_firm_capitals,
            'Cap.Firms': self.k_firm_inventories,
            'Total': self.c_firm_capitals + self.k_firm_inventories,
        }
        bonds_ = {
            'Bank': self.banks_hold_bonds_as_assets,
            'Gov': -self.gov_bonds_issue_as_dept,
            'Central Bank': self.central_bank_hold_bonds_as_assets,
            'Total': self.banks_hold_bonds_as_assets + self.central_bank_hold_bonds_as_assets - self.gov_bonds_issue_as_dept
        }
        reserves_ = {
            'Bank': self.bank_hold_reserve_as_assets,
            'Central Bank': -self.central_bank_hold_reserve_as_dept,
            'Total': self.bank_hold_reserve_as_assets - self.central_bank_hold_reserve_as_dept}
        # advances_ = {'Household': 0, 'Cons.Firms': 0, 'Cap.Firms': 0, 'Bank': 0, 'Gov': 0,
        #              'Central Bank': 0, 'Total': 0}
        ddf = pd.DataFrame(
            {
                'Deposits': deposits_,
                'Loans': loans_,
                'Con.Goods': con_goods_,
                'Cap.Goods': cap_goods_,
                'Bonds': bonds_,
                'Reserve': reserves_,
                            }
            )
        ddf = ddf.round(1)
        ddf = ddf.fillna(0)
        ddf['Net Worth'] = ddf.sum(axis=1)
        ddf = ddf.T
        show_cols = ['Households', 'Cons.Firms', 'Cap.Firms', 'Bank', 'Gov', 'Central Bank', 'Total']
        df_show = ddf.loc[:, show_cols]
        if prt:
            print(self.e.year, 'Monitor balance sheet')
            print(df_show)
        return df_show

    def check_deposits(self):
        apt(f"【居民企业视角】存款作为资产:{self.deposits_as_assets:.1f}, "
            f"【居民】:{self.households_deposits_as_assets:.1f}"
            f"【C公司】:{self.c_firms_deposits_as_assets:.1f}"
            f"【K公司】:{self.k_firms_deposits_as_assets:.1f}"
            f"【银行视角】存款作为负债:{self.deposits_as_debt:.1f}")
        if abs(self.deposits_as_assets - self.deposits_as_debt) > 1:
            print(f"!!!!!!!存款资产验证失败!!!!!!!!")
        else:
            apt(">>>>【资产负债表验证】居民+企业存款资产 等于 银行存款负债")

    def check_loans(self):
        apt(f"【居民企业视角】贷款作为负债:{self.firms_loans_as_dept:.1f}, "
            f"【C公司】{self.c_firms_loans_as_dept:.1f}"
            f"【K公司】{self.k_firms_loans_as_dept:.1f}"
            f"【银行视角】贷款作为资产:{self.banks_loans_as_assets:.1f}")
        if abs(self.firms_loans_as_dept - self.banks_loans_as_assets) > 1:
            print(f"!!!!!!!贷款资产验证失败!!!!!!!!")
        else:
            apt(">>>>【资产负债表验证】居民+企业贷款负债 等于 银行存款资产")

    def check_bonds(self):
        bank_and_cb_bank_hold_bonds = self.banks_hold_bonds_as_assets + self.central_bank_hold_bonds_as_assets
        apt(f"【政府视角】债券作为负债:{self.gov_bonds_issue_as_dept:.1f},"
            f"【中央银行和银行视角】债券作为资产:{bank_and_cb_bank_hold_bonds:.1f}")
        if abs(bank_and_cb_bank_hold_bonds - self.gov_bonds_issue_as_dept) > 1:
            print(f"!!!!!!!债券验证失败!!!!!!!!")
        else:
            apt(">>>>【资产负债表验证】银行+中央银行债券资产 等于 政府债券负债")

    def check_cash_advance(self):
        apt(f"【银行视角】现金预借款作为负债:{self.bank_hold_cash_advance_as_dept:.1f}"
            f"【中央银行视角】现金预借款作为资产:{self.central_bank_hold_cash_advance_as_assets:.1f}")
        if abs(self.bank_hold_cash_advance_as_dept - self.central_bank_hold_cash_advance_as_assets) > 1:
            print(f"!!!!!!!现金预借款验证失败!!!!!!!!")
        else:
            apt(">>>>【资产负债表验证】中央银行现金预借款资产 等于 银行现金预借款负债")

    def check_reserves(self):
        apt(f"【银行视角】保证金作为资产:{self.bank_hold_reserve_as_assets:.1f}"
            f"【中央银行视角】保证金作为负债:{self.central_bank_hold_reserve_as_dept:.1f}")
        if abs(self.bank_hold_reserve_as_assets - self.central_bank_hold_reserve_as_dept) > 1:
            print(f"!!!!!!!保证金验证失败!!!!!!!!")
        else:
            apt(">>>>【资产负债表验证】中央银行现金保证金负债 等于 银行保证金资产")

    def all_deposits_in_banks_as_debt(self):
        all_obj_dep = 0
        for b in self.e.credit_market.banks:
            all_obj_dep += np.sum([c.amount for _, c in b.deposits_contracts.items()])
        return all_obj_dep

    @staticmethod
    def sum_batch_loans(firms: List[Firms]):
        all_obj_loans = 0
        for c_firm in firms:
            for loan_contracts in c_firm.batch_of_loan_contracts:
                all_obj_loans += loan_contracts.amount
        return all_obj_loans

    def sum_dict_loans(self):
        all_obj_loans = 0
        for bank in self.e.credit_market.banks:
            for _, batch_loan in bank.loans_contracts.items():
                all_obj_loans += np.sum([loan_contract.amount for loan_contract in batch_loan])
        return all_obj_loans

    def sum_batch_bonds(self):
        all_obj_bonds = 0
        for bank in self.e.credit_market.banks:
            for bond_contract in bank.bonds_contracts:
                all_obj_bonds += bond_contract.amount
        return all_obj_bonds


class CheckConsistencyMonitor:
    def __init__(self, bs_monitor: BalanceSheetMonitor, tf_monitor: TransactionFlowMonitor):
        self.bs_monitor = bs_monitor
        self.tf_monitor = tf_monitor
        